#ifndef __BIT_FIELD__
#define __BIT_FIELD__

#include <iostream>
#include <inttypes.h>

#include "exceptions.h"

using namespace std;

template<class T>
void set_bit (T& n, int bit)
{
  n |= 1 << bit;
}

template<class T>
void clr_bit (T& n, int bit)
{
  n &= ~(1 << bit);
}

template<class T>
void set_bit_value (T& n, int bit, int v)
{
  if (v)
    set_bit<T> (n, bit);
  else
    clr_bit<T> (n, bit);
}

template<class T>
int get_bit (T n, int bit)
{
  return (int)((n >> bit) & 0x1);
}

template<class T>
void set_byte (T& n, uint8_t byte_no, uint8_t byte)
{
  n &= ~(((T)0xff) << (byte_no * 8));
  n |= ((T)byte) << (byte_no * 8);
}

template<class T>
uint8_t get_byte (T n, uint8_t byte_no)
{
  return (uint8_t)(n >> (byte_no * 8)) & 0xff;
}

template<class T>
T unpack_mask (T n, T mask)
{
  T ret = 0;
  int nrshift = 0;

  for (int i = 0; i < (int)(sizeof (T) * 8); ++i) {
    if (mask & 0x1)
      ret |= (n & 0x1) << nrshift++;

    n >>= 1;
    mask >>= 1;
  }

  return ret;
}

template<typename T>
class Bit
{
public:
  Bit (bool value = false)
  {
    _field = 0;
    _value = value;
  }

  Bit (T* field, unsigned int bit)
  {
    _field = field;
    _bit = bit;
  }

  const Bit<T>& operator= (const Bit<T>& b)
  {
    if (_field) {
      clr_bit<T> (*_field, _bit);
      *_field |= (T)b << _bit;
    }
    else
      _value = (bool)b;

    return *this;
  }

#if 0
  const Bit<T>& operator= (T value)
  {
    if (_field) {
      if (value)
        set_bit<T> (*_field, _bit);
      else
        clr_bit<T> (*_field, _bit);
    }
    else
      _value = value != 0;

    return *this;
  }
#endif

  const Bit<T>& operator= (bool value)
  {
    if (_field) {
      if (value)
        set_bit<T> (*_field, _bit);
      else
        clr_bit<T> (*_field, _bit);
    }
    else
      _value = value;

    return *this;
  }

  const Bit<T>& operator&= (const Bit<T>& b)
  {
    if (_field)
      *_field &= (T)b << _bit;
    else
      _value = _value && (bool)b;

    return *this;
  }

  const Bit<T>& operator|= (const Bit<T>& b)
  {
    if (_field)
      *_field |= (T)b << _bit;
    else
      _value = _value || (bool)b;

    return *this;
  }

  const Bit<T>& operator^= (const Bit<T>& b)
  {
    if (_field)
      *_field ^= (T)b << _bit;
    else
      _value = _value != (bool)b;

    return *this;
  }

  const Bit<T>& operator~ ()
  {
    if (_field)
      *_field ^= 1 << _bit;
    else
      _value = !_value;

    return *this;
  }

  Bit<T> operator& (bool b) const
  {
    return Bit<T> ((bool)*this && b);
  }

  Bit<T> operator| (bool b) const
  {
    return Bit<T> ((bool)*this || (bool)b);
  }

  Bit<T> operator^ (bool b) const
  {
    return Bit<T> ((bool)*this != (bool)b);
  }

  Bit<T> operator! () const
  {
    return Bit<T> (!(bool)*this);
  }

  operator T () const
  {
    if (_field)
      return (*_field >> _bit) & 1;

    return _value ? 1 : 0;
  }

  operator bool () const
  {
    if (_field)
      return ((*_field >> _bit) & 1) == 1;

    return _value;
  }

private:
  bool _value;
  T* _field;
  unsigned int _bit;
};

template<typename T>
class BitField
{
public:
  BitField () { }

  BitField (T value)
  {
    _field = value;
  }

  const BitField<T>& operator= (T value)
  {
    _field = value;
    return *this;
  }

  const BitField<T>& operator<<= (unsigned int shift)
  {
    _field <<= shift;
    return *this;
  }

  const BitField<T>& operator>>= (unsigned int shift)
  {
    _field >>= shift;
    return *this;
  }

  const BitField<T>& operator&= (T value)
  {
    _field &= value;
    return *this;
  }

  const BitField<T>& operator|= (T value)
  {
    _field |= value;
    return *this;
  }

  const BitField<T>& operator^= (T value)
  {
    _field ^= value;
    return *this;
  }

  /* Since BitField can typecase to type T all the non-assignment
   * bitwise operators can be taken care of via the build-in type operators */

  Bit<T> operator[] (unsigned int bit) const
  {
    if (bit >= sizeof (T) * 8)
      throw IndexException ();

    return Bit<T> (((_field >> bit) & 1) == 1);
  }

  Bit<T> operator[] (unsigned int bit)
  {
    if (bit >= sizeof (T) * 8)
      throw IndexException ();

    return Bit<T> (&_field, bit);
  }

  operator T () const { return _field; }
  operator T () { return _field; }

  uint8_t get_byte (unsigned int byte) const
  {
    return ::get_byte<T> (_field, byte);
  }

  void set_byte (unsigned int byte, uint8_t value)
  {
    ::set_byte<T> (_field, byte, value);
  }

protected:
  T _field;
};

#endif /* __BIT_FIELD__ */
